//
// Created by benxb on 2021/12/12.
//

#include "index/linear_index_page.h"
#include <common/logger.h>

namespace benxdb {

LinearIndexPage::LinearIndexPage() {

}

LinearIndexPage::~LinearIndexPage() = default;

void LinearIndexPage::AppendIndexPair(LinearIndexLeafPair &pair) {
    if (!HasFreeSlot()) {
        return;
    }
    pair.SerializeTo(GetData() + OFFSET_INDEX_BEGIN + GetIndexSize() * GetIndexPairSize());
    SetIndexSize(GetIndexSize()+1);
}

void LinearIndexPage::SetPageID(page_id_t page_id) {
    memcpy(GetData() + OFFSET_PAGE_ID, &page_id, sizeof(page_id));
}

page_id_t LinearIndexPage::GetPageID() {
    return *reinterpret_cast<page_id_t *> (GetData() + OFFSET_PAGE_ID);
}

void LinearIndexPage::SetIndexSize(uint32_t index_size) {
    memcpy(GetData() + OFFSET_INDEX_SIZE, &index_size, sizeof(index_size));
}

uint32_t LinearIndexPage::GetIndexSize() {
    return *reinterpret_cast<uint32_t *> (GetData() + OFFSET_INDEX_SIZE);
}

uint32_t LinearIndexPage::GetFreeSlotSize() {
    return GetMaxIndexCount() - GetIndexSize();
}

void LinearIndexPage::AppendIndexPairs(std::vector<LinearIndexLeafPair> &pairs) {
    if (!HasFreeSlot(pairs.size())) {
        return;
    }
    int index = GetIndexSize();
    for (auto& pair : pairs) {
        pair.SerializeTo(GetData() + OFFSET_INDEX_BEGIN + index * GetIndexPairSize());
        index++;
    }
    SetIndexSize(GetIndexSize()+pairs.size());
}

bool LinearIndexPage::HasFreeSlot() {
    return GetFreeSlotSize() > 0;
}

void LinearIndexPage::ClearIndex() {
    SetIndexSize(0);
}

LinearIndexLeafPair LinearIndexPage::GetIndexPair(int index) {
    return LinearIndexLeafPair::DeserializeFrom(GetData() + OFFSET_INDEX_BEGIN + index * GetIndexPairSize(),
                                                GetKeyType());
}

LinearIndexKeyType LinearIndexPage::GetKeyType() {
    return *reinterpret_cast<LinearIndexKeyType *> (GetData() + OFFSET_INDEX_KEY_TYPE);
}

void LinearIndexPage::SetKeyType(LinearIndexKeyType type) {
    memcpy(GetData() + OFFSET_INDEX_KEY_TYPE, &type, sizeof(type));
}

LinearIndexPage::LinearIndexPage(LinearIndexKeyType type) {
    SetKeyType(type);
    SetIndexSize(0);
}

bool LinearIndexPage::HasFreeSlot(int index_count) {
    return GetFreeSlotSize() >= index_count;
}

uint32_t LinearIndexPage::GetMaxIndexCount() {
    return (PAGE_SIZE - OFFSET_INDEX_BEGIN)/LinearIndexLeafPair::SizeOfKeyType(GetKeyType());
}

int LinearIndexPage::GetIndexPairSize() {
    return LinearIndexLeafPair::SizeOfKeyType(GetKeyType());
}

int LinearIndexLeafPair::SerializeTo(char *storage) {
    int res = key.SerializeTo(storage);
    *reinterpret_cast<record_id_t *>(storage+res) = record_id;
    res += sizeof(record_id_t);
    return res;
}

LinearIndexLeafPair::LinearIndexLeafPair(LinearIndexKeyType type, const char *data) : key(type, data) {
    int key_size = key.GetSize();
    record_id = *reinterpret_cast<const record_id_t*>(data + key_size);
}

LinearIndexLeafPair LinearIndexLeafPair::DeserializeFrom(const char *storage, LinearIndexKeyType type) {
    return LinearIndexLeafPair(type, storage);
}

int LinearIndexLeafPair::GetSize() {
    return key.GetSize() + sizeof(record_id_t);
}

int LinearIndexLeafPair::SizeOfKeyType(LinearIndexKeyType type) {
    return LinearIndexKey::GetSizeOfType(type) + sizeof(record_id_t);
}
}
